﻿/*右键菜单定义--GooContextMenu类*/
//contextDiv:JQUERY对象，要渲染的DOM
//menuWidth 数字，菜单的宽度;
//menuContent,JSON数据，格式在DEMO页面中
//bindingFun要绑定的函数方法组合,JSON数据
//行高一律定为22PX+2px的边框
//分隔符的高一律定为5px
//构造完后，还需要行另外的初始化(如加入单元,绑定展示所需事件)才能用
function GooContextMenu(contextDiv, menuWidth) {
    this.$contextDiv = contextDiv;
    this.$menuWidth = menuWidth;
    this.$numList = 0;
    this.$numHr = 0;
    this.$contextDiv.toggleClass("contextMenu");
    this.$contextDiv.css({ width: menuWidth + "px" });
    this.$target = null; //(右击)触发菜单打开对象的ID
    this.$funBind = []; //菜单中每个结点单击后触发事件的FUNCION数组集
    this.$makeShow = ""; //导致显示右键菜单的事件名称，如单击是"click",右击是"contextmenu"
    this.$showChildId = null; //正在显示子菜单的非叶子结点ID
    this.$childMenu = []; //本菜单所有的子菜单数组，单元为一个GooContextMenu对象，索引为该子菜单的父结点ID
    this.$listHeight = 4;
    this.$menuDiv = $("<div class='menuLists' style='width:" + (menuWidth - 9) + "px'></div>");
    this.$contextDiv.append(this.$menuDiv);
    this.$contextDiv.append("<div class='rightShadow' style='height:" + (this.$listHeight - 1) + "px'></div><div class='bottomShadow' style='width:" + (menuWidth - 4) + "px'></div>");
    //this.appendItemList(menuContent,bindingFun);
    /*以上为构造方法，下面开始类内其它方法的定义*/
    this.bindClick();
    this.bindMouseOver();
}


GooContextMenu.prototype = {
    show: function (e) {
        ev = mousePosition(e);
        var bodyWidth = document.documentElement.scrollWidth;
        var bodyHeight = document.documentElement.scrollHeight > document.documentElement.clientHeight ? document.documentElement.scrollHeight : document.documentElement.clientHeight;
        if (ev.x + this.$menuWidth > bodyWidth)
            ev.x = ev.x - this.$menuWidth;
        if (ev.y + this.$listHeight + 5 > bodyHeight)
            ev.y = bodyHeight - this.$listHeight - 5;
        this.$contextDiv.hide();
        this.$contextDiv.css({ left: ev.x + "px", top: ev.y + "px" });
        this.$contextDiv.show(60);
    },
    show2: function (left, top) {
        this.$contextDiv.hide();
        this.$contextDiv.css({ left: left + "px", top: top + "px" });
        this.$contextDiv.show(60);
    },

    hide: function () {
        for (var key in this.$childMenu)
            this.$childMenu[key].hide();
        this.$contextDiv.hide();
    },
    //设置菜单单元（可以是子菜单中的）的图标样式，传参:id为单元DOM的ID，cls为样式类名称
    setIcon: function (id, cls) {
        $("#" + id).children("b").attr("className", cls);
    },
    //获取菜单单元（可以是子菜单中的）的图标样式，传参:id为单元DOM的ID
    getIcon: function (id) {
        return $("#" + id).children("b").attr("className");
    },
    //设置菜单单元（可以是子菜单中的）的文字，传参:id为单元DOM的ID，text为文字内容
    setText: function (id, text) {
        $("#" + id).children("span").text(text);
    },
    //获取菜单单元（可以是子菜单中的）的文字，传参:id为单元DOM的ID
    getText: function (id) {
        return $("#" + id).children("span").text();
    },
    //加入一个菜单项()方法可选
    appendItem: function (newItem, seq, order, fun) {
        innerList = "";
        if (newItem.id != null) {
            innerList += "<a class='";
            this.$numList += 1;
            if (newItem.disable)
                innerList += "disable' href='javascript:' id='" + newItem.id + "'>";
            else
                innerList += "item' href='javascript:' id='" + newItem.id + "'>";
            if (newItem.cls != null)
                innerList += "<b class='" + newItem.cls + "'></b>";
            else innerList += "<b></b>";
            innerList += "<span>" + newItem.text + "</span>";
            if (newItem.childItem) {
                innerList += "<em></em></a>";
                /*this.$contextDiv.after("<div id='child_"+newItem.id+"'></div>");
                this.$childMenu[newItem.id]=$.createGooContextMenu($("#child_"+newItem.id),this.$menuWidth,newItem.childItems,newItem.childFuns);*/
            }
            else innerList += "</a>";
            this.$listHeight += 24;
            this.$contextDiv.children(".rightShadow").css({ height: (this.$listHeight - 1) + 'px' });
        }
        else if (newItem.hr == '') {
            innerList += "<p class='hr'></p>";
            this.$numHr += 1;
            this.$listHeight += 5;
            this.$contextDiv.children(".rightShadow").css({ height: (this.$listHeight - 1) + 'px' });
        }
        if (order == "before")
            this.$menuDiv.children("a:eq(" + (seq - 1) + ")").before(innerList);
        else if (order == "first")
            this.$menuDiv.append(innerList);
        else
            this.$menuDiv.children("a:eq(" + (seq - 1) + ")").after(innerList);
        this.$funBind[newItem.id] = fun;
        if (newItem.childItems)
            this.attentChildMenu(newItem.id, newItem.childItems, childFuns);
    },
    //增加一组菜单项,参数menuContent与bindingFun:与初始化构造函数中的同名参数意义和结构都一样
    appendItemList: function (menuContent, bindingFun) {
        var innerList = "";
        for (i = 0; i < menuContent.length; ++i) {
            if (menuContent[i].id != null) {
                innerList += "<a class='";
                this.$numList += 1;
                if (menuContent[i].disable)
                    innerList += "disable' href='javascript:' id='" + menuContent[i].id + "'>"
                else
                    innerList += "item' href='javascript:' id='" + menuContent[i].id + "'>";
                if (menuContent[i].cls != null)
                    innerList += "<b class='" + menuContent[i].cls + "'></b>";
                else innerList += "<b></b>";
                innerList += "<span>" + menuContent[i].text + "</span>";
                if (menuContent[i].childItems) {
                    innerList += "<em></em></a>";
                }
                else innerList += "</a>";
                this.$listHeight += 24;
                if (bindingFun[menuContent[i].id])
                    this.$funBind[menuContent[i].id] = bindingFun[menuContent[i].id];
            }
            else if (menuContent[i].hr == '') {
                innerList += "<p class='hr'></p>";
                this.$numHr += 1;
                this.$listHeight += 5;
            }
        }
        this.$menuDiv.append(innerList);
        this.$contextDiv.children(".rightShadow").css({ height: (this.$listHeight - 1) + 'px' });
        for (i = 0; i < menuContent.length; ++i) {
            if (menuContent[i].childItems)
                this.attentChildMenu(menuContent[i].id, menuContent[i].childItems, childFuns);
        }
    },
    //删除一个菜单项
    removeItem: function (seq) {
        var id = this.$menuDiv.children("a:eq(" + (seq - 1) + ")").children("p").attr("id");
        if (id != null) {
            if (this.$menuDiv.children("#" + id).children("em").length == 0) this.remvoeChildMenu(id);
            this.$menuDiv.children("a:eq(" + (seq - 1) + ")").remove();
            this.$funBind[id] = null;
            this.$listHeight -= 24;
            this.$contextDiv.children(".rightShadow").css({ height: (this.$listHeight - 1) + 'px' });
        }
    },
    removeItem2: function (id) {
        if (id != null) {
            if (this.$menuDiv.children("#" + id).children("em").length == 0) this.remvoeChildMenu(id);
            this.$menuDiv.children("#" + id).remove();
            this.$funBind[id] = null;
            this.$listHeight -= 24;
            this.$contextDiv.children(".rightShadow").css({ height: (this.$listHeight - 1) + 'px' });
        }
    },

    //删除一个分隔符
    removeHr: function (seq) {
        var temp = this.$menuDiv.children("p:eq(" + (seq - 1) + ")");
        if (temp != null) {
            temp.remove();
            this.$listHeight -= 5;
            this.$contextDiv.children(".rightShadow").css({ height: (this.$listHeight - 1) + 'px' });
        }
    },
    //使一个菜单项能使用/作废不能使用但仍显示,方法不删除
    ableItem: function (seq, able) {
        var temp = this.$menuDiv.children("a:eq(" + (seq - 1) + ")");
        temp.removeClass();
        if (able) {
            temp.addClass("item");
            temp.attr("href", "javascript:");
        }
        else {
            temp.addClass("disable");
            temp.removeAttr("href");
        }
    },
    //在目标的JQUERY对象上取消绑定右键
    unbind: function (jq) {
        jq.unbind(this.$makeShow);
        this.$makeShow = "";
    },
    //彻底删除自己和所有可能存在的子菜单
    remove: function () {
        for (var key in this.$childMenu) {
            this.$childMenu[key].remove();
        }
        this.$childMenu = null;
        this.$childMenu = [];
        this.$contextDiv.remove();
    },
    //彻底删除某个父ID为传参id的子菜单，所属父结点变成叶子结点
    remvoeChildMenu: function (id) {
        this.$childMenu[id].remove();
        this.$menuDiv.children("#" + id).children("em").remove();
    },
    //扩展某个菜单叶子结点为非叶子结点，附加上一个子菜单GooContextMenu对象
    //id为菜单单元的ID，menuContent，bindingFuns的数据结构定义与GooContextMenu构造函数中的同名传参一样
    attentChildMenu: function (id, menuContent, bindingFuns) {
        if (this.$childMenu[id]) return; //如果该结点已经是非叶子结点，则无法完成扩展，直接退出
        var temp = this.$menuDiv.children("#" + id);
        if (temp.children("em").length == 0) temp.append("<em></em>");
        this.$contextDiv.after("<div id='child_" + id + "'></div>");
        this.$childMenu[id] = $.createGooContextMenu($("#child_" + id), this.$menuWidth, menuContent, bindingFuns);
    },

    //绑定一个父框架以操作里面的多项子元素（只需绑定一次），用来代替对每个子元素都绑定一次的方法，
    //(参数jq为一个JQUERY对象)
    //attrName,attrValue : 是用来作判断右键菜单是否弹出的条件，条件来自于绑定对象的属性中.
    bindParent: function (jq, attrName, attrValue, Event) {
        this.$makeShow = Event;
        var inthis = this;
        jq.bind(Event, function (e) {
            var clicked = e.target;
            if (clicked.getAttribute("id") == this.getAttribute("id")) return true;
            else if (attrName && clicked.getAttribute(attrName) != attrValue) return true;
            else {
                //
                inthis.$target = clicked.CaiID || ""; //clicked.id || "";
                inthis.show(e);
                $(document).one("click", function () {
                    inthis.hide();
                });
                return false;
            }
        });
    },

    //绑定菜单栏中,当一个项目被点击时触发的事件
    bindClick: function () {
        var inthis = this;
        this.$menuDiv.bind('click', function (e) {
            var $clicked = $(e.target);
            if ($clicked.attr("tagName") != "A")
                $clicked = $clicked.parent();
            if ($clicked.attr("className") == 'item') {
                if ($clicked.children("em").length > 0) return false;
                else if (inthis.$funBind[$clicked.attr("id")])
                    inthis.$funBind[$clicked.attr("id")]($clicked.attr("id"), inthis.$target);
            }
        });
    },

    //绑定菜单栏中,判断一个项目是否为非叶子项目，并展示滑过的非叶子项目的子菜单
    bindMouseOver: function (aid) {
        var inthis = this;
        this.$menuDiv.bind('mouseover', function (e) {
            var haveChild = false;
            //alert("fcuk");
            var move = null;
            switch (e.target.tagName) {
                case "EM":
                    haveChild = true;
                    move = e.target.parentNode;
                    break;
                case "B":
                case "SPAN":
                    move = e.target.parentNode;
                    if (move.lastChild.tagName == "EM")
                        haveChild = true;
                    break;
                case "A":
                    move = e.target;
                    if (move.lastChild.tagName == "EM")
                        haveChild = true;
                    break;
            }
            if (haveChild && move) {
                var bodyWidth = document.documentElement.scrollWidth;
                var bodyHeight = document.documentElement.scrollHeight > document.documentElement.clientHeight ? document.documentElement.scrollHeight : document.documentElement.clientHeight;
                if (inthis.$showChildId && inthis.$showChildId != move.id) {
                    var t = getElCoordinate(move);
                    t.left = t.left + inthis.$menuWidth - 9;
                    if (t.left + inthis.$menuWidth > bodyWidth)
                        t.left = t.left - 2 * inthis.$menuWidth + 13;
                    if (t.top + inthis.$childMenu[move.id].$listHeight + 5 > bodyHeight)
                        t.top = bodyHeight - inthis.$childMenu[move.id].$listHeight - 5;
                    inthis.$childMenu[inthis.$showChildId].$contextDiv.stop(true, true);
                    inthis.$childMenu[inthis.$showChildId].hide();
                    inthis.$menuDiv.children("#" + inthis.$showChildId).removeClass("unfold");
                    inthis.$childMenu[move.id].$target = inthis.$target;
                    inthis.$childMenu[move.id].show2(t.left, t.top);
                    $(move).addClass("unfold");
                    inthis.$showChildId = move.id;
                }
                else if (!inthis.$showChildId) {
                    var t = getElCoordinate(move);
                    t.left = t.left + inthis.$menuWidth - 9;
                    if (t.left + inthis.$menuWidth > bodyWidth)
                        t.left = t.left - 2 * inthis.$menuWidth + 13;
                    if (t.top + inthis.$childMenu[move.id].$listHeight + 5 > bodyHeight)
                        t.top = bodyHeight - inthis.$childMenu[move.id].$listHeight - 5;
                    inthis.$childMenu[move.id].$target = inthis.$target;
                    inthis.$childMenu[move.id].show2(t.left, t.top);
                    $(move).addClass("unfold");
                    inthis.$showChildId = move.id;
                }
            }
            else {
                if (inthis.$showChildId) {
                    inthis.$childMenu[inthis.$showChildId].$contextDiv.stop(true, true);
                    inthis.$childMenu[inthis.$showChildId].hide();
                    inthis.$menuDiv.children("#" + inthis.$showChildId).removeClass("unfold");
                    inthis.$showChildId = null;
                }
            }
        });
    },
    //单单只绑定一个DOM元素(参数jq为一个JQUERY对象)
    bindObject: function (jq, Event) {
        this.$makeShow = Event;
        var inthis = this;
        jq.bind(Event, function (e) {
            inthis.$target = this.id || "";
            inthis.show(e);
            $(document).one("click", function () {
                inthis.hide();
            });
            return false;
        });
    }
}

//将此类的构造函数加入至JQUERY对象中
jQuery.extend({
    createGooContextMenu: function (contextDiv, menuWidth, menuContent, bindingFun) {
        var obj = new GooContextMenu(contextDiv, menuWidth);
        /*for(var i=0;i<menuContent.length;++i){
        if(menuContent[i].childItems){
        obj.$contextDiv.after("<div id='child_"+menuContent[i].id+"'></div>");
        obj.$childMenu[menuContent[i].id]=$.createGooContextMenu($("#child_"+menuContent[i].id),menuWidth,menuContent[i].childItems,menuContent[i].childFuns);
        }
        }*/
        obj.appendItemList(menuContent, bindingFun);
        return obj;
    }
}); 